package com.zy.sso.server.service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import com.zy.sso.client.component.SpringComponent;
import com.zy.sso.client.dto.BaseUser;
import com.zy.sso.client.dto.change_user_status.ChangeUserStatusDTO;
import com.zy.sso.client.dto.find_pwd.FindPwdDTO;
import com.zy.sso.client.dto.login.ClientInfo;
import com.zy.sso.client.dto.login.LoginDTO;
import com.zy.sso.client.dto.logout.LogoutDTO;
import com.zy.sso.client.dto.reset_pwd.ResetPwdDTO;
import com.zy.sso.client.exception.SsoException;
import com.zy.sso.server.entites.ClientTrack;
import com.zy.sso.server.entites.User;
import com.zy.sso.server.event.LoginEvent;
import com.zy.sso.server.event.LogoutEvent;
import com.zy.sso.server.event.RegisterEvent;
import com.zy.sso.server.repository.UserRepository;



@Service
@CacheConfig(cacheNames = "users")
public class UserService{
	
	private static final Logger logger =  LoggerFactory.getLogger(UserService.class);
	
	public static final String SSO_SERVER_CHACE_ACCOUNT_PIX = "sso_account_";
	
	@Autowired
	private UserRepository userRepository;

	@Autowired
	private SpringComponent springComponent;

	@Autowired
	private MongoTemplate mongoTemplate;

	@Autowired
	private ApplicationEventPublisher applicationEventPublisher;


	/**
	 * 说明:用户注冊
	 * @param loginDTO
	 * @return JwtUser
	 * **/
	public BaseUser regist(LoginDTO loginDTO){
		//insert user info
		User user = userRepository.findOneByAccount(loginDTO.getAccount());
		if(user != null) {
			//销户提示
			if(user.getStatus() == BaseUser.UserStatus.cancellation){
				logger.error("该账号已销户,请换一个账号注册！account:{}",loginDTO.getAccount());
				throw new SsoException("该账号已销户,请换一个账号注册!");
			}
			//普通提示
			logger.error("账号已经存在:{}",loginDTO.getAccount());
			throw new SsoException("该账号已经存在");
		}
		User.UserBuilder builder= new User.UserBuilder(loginDTO.getAccount(),loginDTO.getPassword());
		builder.buildEncrypeClass(loginDTO.getPasswordEncoder());
		builder.buildFromSystem(loginDTO.getFromSys());
		builder.buildStatus(BaseUser.UserStatus.normal);
		User u = userRepository.save(builder.build());
		//发布通知
		applicationEventPublisher.publishEvent(new RegisterEvent(loginDTO));
		//置空密码
		u.setPassword("");
		return u;
	}

	
	/**
	 * 说明:用户登陆
	 * @param loginDTO
	 * @return JwtUser
	 * @throws ClassNotFoundException 
	 * **/
	public BaseUser login(LoginDTO loginDTO) throws ClassNotFoundException{
		//校验用户信息
		User user = userRepository.findOneByAccount(loginDTO.getAccount());
		if(user == null){
			logger.error("用户不存在account:{}",loginDTO.getAccount());
			throw new SsoException("账号不存在,请注册!");
		}
		if(loginDTO.getValidatePwd()){//是否需要验证密码
			String encoder = user.getEncrypeClass();
			if(StringUtils.isEmpty(encoder)) throw new SsoException("加密的encoder类为空");
			PasswordEncoder encode = (PasswordEncoder) springComponent.getBean(Class.forName(encoder));
			boolean flag = encode.matches(loginDTO.getPassword(), user.getPassword());
			if(!flag) throw new SsoException("用户名密码不匹配");
		}
		if(user.getStatus() == BaseUser.UserStatus.init){
			logger.error("请先激活后在登陆account:{}",loginDTO.getAccount());
			throw new SsoException("请先激活后在登陆");
		}
		if(user.getStatus() == BaseUser.UserStatus.frozen){
			logger.error("账号冻结,请联系客服account:{}",loginDTO.getAccount());
			throw new SsoException("账号冻结,请联系客服");
		}
		if(user.getStatus() == BaseUser.UserStatus.cancellation){
			logger.error("该账号已销户,请重新注册！account:{}",loginDTO.getAccount());
			throw new SsoException("该账号已销户,请重新注册!");
		}
		//发布通知
		applicationEventPublisher.publishEvent(new LoginEvent(loginDTO));
		user.setPassword("");
		return user;
	}
	
	/**
	 * 说明:退出登陆
	 * @param gid
	 * @return JwtUser
	 * **/
	public void loginOut(LogoutDTO logoutDto, String gid){
		User user = userRepository.findOneByGid(gid);
		if(user == null) {
			logger.error("用户不存在--->gid:{}",gid);
			throw new SsoException("用户不存在");
		}
		if(!user.getGid().equals(gid)) {
			logger.error("请求参数不一致--》gid:{}",gid);
			throw new SsoException("请求参数不一致");
		}
		//发布通知
		applicationEventPublisher.publishEvent(new LogoutEvent(logoutDto));
	}
	
	
	/**
	 * 说明:找回密码
	 * @param findPwdDto
	 * @param account
	 * @return JwtUser
	 * **/
	@CachePut(key = "'"+SSO_SERVER_CHACE_ACCOUNT_PIX+"'+#account")
	public BaseUser findPwd(FindPwdDTO findPwdDto, String account){
		if(!findPwdDto.getAccount().equals(account)){
			logger.error("请求参数不一致--》account:{}",account);
			throw new SsoException("请求参数不一致");
		}
		User user = userRepository.findOneByAccount(account);
		if(user == null) {
			logger.error("用户不存在--》account:{}",account);
			throw new SsoException("用户不存在");
		}
		user.setEncrypeClass(findPwdDto.getPasswordEncoder());
		user.setFromSystem(findPwdDto.getFromSys());
		user.setPassword(findPwdDto.getNewPassword());
		user.setUpdateTime(LocalDateTime.now());
		userRepository.save(user);
		user.setPassword("");
		return user;
	}
	
	/**
	 * 说明:忘记密码
	 * @param resetPwdDto
	 * @param gid
	 * @return JwtUser
	 * @throws ClassNotFoundException 
	 * **/
	@CachePut(key = "'"+SSO_SERVER_CHACE_ACCOUNT_PIX+"'+#resetPwdDto.account")
	public BaseUser resetPwd(ResetPwdDTO resetPwdDto, String gid) throws ClassNotFoundException{
		User user = userRepository.findOneByAccount(resetPwdDto.getAccount());
		if(user == null) {
			logger.error("用户不存在--》account:{}",resetPwdDto.getAccount());
			throw new SsoException("用户不存在");
		}
		if(!gid.equals(user.getGid())){
			logger.error("用户信息错误--》account:{},gid:{}",resetPwdDto.getAccount(),gid);
			throw new SsoException("用户信息错误");
		}
		//校验旧密码
		String encoder = user.getEncrypeClass();
		if(StringUtils.isEmpty(encoder)) throw new SsoException("加密的encoder类为空");
		PasswordEncoder encode = (PasswordEncoder) springComponent.getBean(Class.forName(encoder));
		boolean flag = encode.matches(resetPwdDto.getOldPassword(), user.getPassword());
		if(!flag) throw new SsoException("旧密码不匹配");
		//设置新密码
		PasswordEncoder newEncode = (PasswordEncoder) springComponent.getBean(Class.forName(resetPwdDto.getPasswordEncoder()));
		user.setPassword(newEncode.encode(resetPwdDto.getNewPassword()));
		user.setUpdateTime(LocalDateTime.now());
		user.setEncrypeClass(resetPwdDto.getPasswordEncoder());
		user.setFromSystem(resetPwdDto.getFromSys());
		userRepository.save(user);
		user.setPassword("");
		return user;
	}
	
	/**
	 * 说明:获取用户登陆信息(最新10条)
	 * @param gid
	 * @return JwtUser
	 * **/
	public List<ClientInfo> getLoginInfoByGid(String gid){
//		int pageSize = 10;
//		Query query = new Query();
//		query.addCriteria(Criteria.where("gid").is(gid));
//		long totalCount = mongoTemplate.count(query,ClientTrack.class);
		
		Query query = new Query();
		query.with(new Sort(Sort.Direction.DESC, "create_time"));
	    query.skip(0);// 从那条记录开始
	    query.limit(10);// 取多少条记录
		return mongoTemplate.find(query, ClientTrack.class).stream().map(s -> {
			ClientInfo t = new ClientInfo();
			BeanUtils.copyProperties(s,t);
			return t;
		}).collect(Collectors.toList());
	}
	
	/**
	 * 说明:获取用户账户信息
	 * @param gid
	 * @return JwtUser
	 * **/
	public BaseUser getAccountInfoByGid(String gid){
		User user = userRepository.findOneByGid(gid);
		user.setPassword("");
		return user;
	}
	
	/**
	 * 说明:获取用户账户信息
	 * @param account
	 * @return JwtUser
	 * **/
	@Cacheable(key = "'"+SSO_SERVER_CHACE_ACCOUNT_PIX+"'+#account")
	public BaseUser getAccountInfoByAccount(String account){
		User user = userRepository.findOneByAccount(account);
		user.setPassword("");
		return user;
	}
	
	/**
	 * 说明:更改用户状态
	 * @param account
	 * @param changeUserStatusDto
	 * @return JwtUser
	 * **/
	@CachePut(key = "'"+SSO_SERVER_CHACE_ACCOUNT_PIX+"'+#account")
	public BaseUser changeUserStatus(String account,ChangeUserStatusDTO changeUserStatusDto){
		User user = userRepository.findOneByAccount(account);
		if(user == null) {
			logger.error("用户不存在--->account:{}",account);
			throw new SsoException("用户不存在");
		}
		if(!user.getGid().equals(changeUserStatusDto.getGid())) {
			logger.error("请求参数不一致--》account:{},gid:{}",account,changeUserStatusDto.getGid());
			throw new SsoException("请求参数不一致");
		}
		user.setStatus(changeUserStatusDto.getStatus());
		userRepository.save(user);
		user.setPassword("");
		return user;
	}

	

	


}
